/**
 * 
 */
package reflexactoring.diagram.action.smelldetection;

import java.util.ArrayList;

import reflexactoring.diagram.action.recommend.suboptimal.FitnessEvaluator;
import reflexactoring.diagram.action.recommend.suboptimal.FitnessEvaluatorFactory;
import reflexactoring.diagram.action.recommend.suboptimal.Genotype;
import reflexactoring.diagram.action.recommend.suboptimal.Violation;
import reflexactoring.diagram.bean.ModuleWrapper;
import reflexactoring.diagram.bean.programmodel.ProgramModel;
import reflexactoring.diagram.util.ReflexactoringUtil;
import reflexactoring.diagram.util.Settings;

/**
 * @author linyun
 *
 */
public class AdvanceEvaluatorAdapter {
	
	private ArrayList<Violation> violationList = new ArrayList<>();
	private double lexicalSim = 0;
	
	public double computeFitness(ProgramModel model, ArrayList<ModuleWrapper> moduleList){
		
		double CBO_Weight=Settings.CBO_Weight;
		double LCOM_Weight=Settings.LCOM_Weight;
		double NOM_Weight=Settings.NOM_Weight;
		double SALF_Weight=Settings.SALF_Weight;
		
		double structureAndLexicalFitness=0.0;
		double CBO=0.0;
		double LCOM=0.0;
		double NOM=0.0;
		double ANTI_NOM=0.0;
		

		if(Settings.NeedHighLevelModel){
			FitnessEvaluator evaluator = FitnessEvaluatorFactory.createFitnessEvaluator(model, moduleList,
					FitnessEvaluator.ADVANCED_EVALUATOR);
			
			System.currentTimeMillis();
			
			int[] DNA = constructDNA(model, moduleList);
			
			Genotype gene = new Genotype(DNA, null, evaluator);
						
			structureAndLexicalFitness = gene.getFitness();
	        //double normalized_structureAndLexicalFitness=Math.pow(Math.E, structureAndLexicalFitness);
	        Settings.SALF=-structureAndLexicalFitness;
			this.violationList = gene.getViolationList();
			this.lexicalSim = gene.getLexicalSim();
		}else{
			Settings.SALF=0.0;
		}
		
		if(Settings.CBO_STATIC){			
			CBO = model.computeNormalizedCBOMetrics();
			Settings.CBO=CBO;
		}else{
			Settings.CBO=0.0;
		}

		if(Settings.LCOM_STATIC){
			LCOM = model.computeNormalizedLCOMMetrics();
			Settings.LCOM=LCOM;
		}else{
			Settings.LCOM=0.0;
		}

		if(Settings.NOM_STATIC){
			NOM = model.computeNormailizedNOMMetrics();
		    ANTI_NOM=1/Math.pow(Math.E, NOM);
			Settings.NOM=NOM;
		}else{
			Settings.NOM=0.0;
		}
		
		

		
		double fitness = -(CBO_Weight*CBO+LCOM_Weight*LCOM)+NOM_Weight*ANTI_NOM+SALF_Weight*structureAndLexicalFitness;
		return fitness;
	}

	/**
	 * @return the violationList
	 */
	public ArrayList<Violation> getViolationList() {
		return violationList;
	}

	/**
	 * @param model
	 * @param moduleList
	 * @return
	 */
	private int[] constructDNA(ProgramModel model,
			ArrayList<ModuleWrapper> moduleList) {
		
		int[] DNA = new int[model.getOutmostTypesInScope().size()];
		for(int i=0; i<DNA.length; i++){
			ModuleWrapper module = model.getOutmostTypesInScope().get(i).getMappingModule();
			int index = ReflexactoringUtil.getModuleIndex(moduleList, module);
			DNA[i] = index;
		}
		
		return DNA;
		
	}

	/**
	 * @return the lexicalSim
	 */
	public double getLexicalSim() {
		return lexicalSim;
	}
	
	
}
